import subprocess
import os
import signal
import time
import logging
from threading import Lock

logger = logging.getLogger(__name__)
stream_lock = Lock()
camera_process = None
is_shutting_down = False

def kill_camera_processes():
    """终止所有可能的相机进程"""
    try:
        # 终止 libcamera 相关进程
        subprocess.run("pkill -f libcamera", shell=True)
        time.sleep(1)  # 等待进程完全终止
        logger.info("已终止所有相机进程")
    except Exception as e:
        logger.error(f"终止相机进程时出错: {str(e)}")

def check_camera_available():
    """检查相机是否可用"""
    try:
        result = subprocess.run(
            "libcamera-still --list-cameras",
            shell=True,
            capture_output=True,
            text=True
        )
        if result.returncode == 0:
            logger.info("相机可用")
            return True
        else:
            logger.error(f"相机不可用: {result.stderr}")
            return False
    except Exception as e:
        logger.error(f"检查相机状态时出错: {str(e)}")
        return False

def capture_with_retry(max_retries=3, retry_delay=2):
    """带重试机制的拍照函数"""
    for attempt in range(max_retries):
        try:
            # 先尝试释放相机资源
            kill_camera_processes()
            time.sleep(retry_delay)
            
            # 检查相机是否可用
            if not check_camera_available():
                logger.error("相机不可用")
                continue
                
            # 执行拍照
            result = subprocess.run(
                "libcamera-jpeg -o /tmp/capture.jpg --width 1280 --height 720",
                shell=True,
                capture_output=True,
                text=True
            )
            
            if result.returncode == 0:
                logger.info("拍照成功")
                return True, "照片已保存到 /tmp/capture.jpg"
            else:
                logger.error(f"拍照失败 (尝试 {attempt + 1}/{max_retries}): {result.stderr}")
                
        except Exception as e:
            logger.error(f"拍照过程出错 (尝试 {attempt + 1}/{max_retries}): {str(e)}")
            
        if attempt < max_retries - 1:
            time.sleep(retry_delay)
    
    return False, "拍照失败，请检查相机是否被其他程序占用"

def generate_frames():
    """生成视频流"""
    global camera_process, is_shutting_down
    with stream_lock:
        try:
            # 如果已有摄像头进程，先终止
            if camera_process:
                try:
                    os.killpg(os.getpgid(camera_process.pid), signal.SIGTERM)
                    camera_process.wait(timeout=2)  # 等待进程结束
                except Exception as e:
                    logger.error(f"终止旧进程时出错: {str(e)}")
                finally:
                    camera_process = None
            
            # 启动 libcamera-vid 捕获视频流
            try:
                camera_process = subprocess.Popen(
                    "libcamera-vid -t 0 --width 1280 --height 720 --framerate 30 --codec mjpeg --output -",
                    shell=True,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    preexec_fn=os.setsid,
                    bufsize=10*1024*1024  # 增加缓冲区大小到10MB
                )
                logger.info("视频流进程已启动，PID: %d", camera_process.pid)
            except Exception as e:
                logger.error(f"启动视频流进程失败: {str(e)}")
                return
            
            # 检查进程是否成功启动
            if camera_process.poll() is not None:
                error = camera_process.stderr.read().decode()
                logger.error(f"视频流进程启动失败: {error}")
                return
            
            # 实时输出视频流
            frame_count = 0
            buffer = b''
            
            while not is_shutting_down:
                try:
                    # 检查进程状态
                    if camera_process.poll() is not None:
                        error = camera_process.stderr.read().decode()
                        logger.error(f"视频流进程已退出: {error}")
                        # 尝试重新启动进程
                        try:
                            camera_process = subprocess.Popen(
                                "libcamera-vid -t 0 --width 1280 --height 720 --framerate 30 --codec mjpeg --output -",
                                shell=True,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE,
                                preexec_fn=os.setsid,
                                bufsize=10*1024*1024
                            )
                            logger.info("重新启动视频流进程，PID: %d", camera_process.pid)
                        except Exception as e:
                            logger.error(f"重新启动视频流进程失败: {str(e)}")
                            return
                        continue

                    # 读取数据到缓冲区
                    chunk = camera_process.stdout.read(8192)  # 每次读取8KB
                    if not chunk:
                        logger.warning("视频流读取为空，检查进程状态")
                        time.sleep(0.1)  # 短暂等待后继续
                        continue
                    
                    buffer += chunk
                    
                    # 查找JPEG帧的开始和结束标记
                    start = buffer.find(b'\xff\xd8')  # JPEG开始标记
                    end = buffer.find(b'\xff\xd9')    # JPEG结束标记
                    
                    # 如果找到完整的JPEG帧
                    if start != -1 and end != -1 and end > start:
                        frame = buffer[start:end+2]  # 包含结束标记
                        buffer = buffer[end+2:]      # 保留剩余数据
                        
                        # 验证帧数据
                        if len(frame) < 100:  # 如果帧数据太小，可能不是有效的JPEG
                            logger.warning(f"帧数据太小 ({len(frame)} bytes)，跳过")
                            continue
                        
                        frame_count += 1
                        if frame_count % 30 == 0:  # 每30帧记录一次
                            logger.info(f"已发送 {frame_count} 帧，当前帧大小: {len(frame)} bytes")
                        
                        # 发送帧数据
                        yield (b'--frame\r\n'
                               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
                    
                    # 如果缓冲区太大，清理一下
                    if len(buffer) > 1024 * 1024:  # 如果超过1MB
                        logger.warning("缓冲区过大，清理数据")
                        buffer = buffer[-1024:]  # 只保留最后1KB
                    
                except Exception as e:
                    logger.error(f"读取视频帧时出错: {str(e)}")
                    time.sleep(0.1)  # 出错时短暂等待
                    continue
                    
        except Exception as e:
            logger.error(f"生成视频流时出错: {str(e)}")
        finally:
            if camera_process:
                try:
                    os.killpg(os.getpgid(camera_process.pid), signal.SIGTERM)
                    camera_process.wait(timeout=2)
                    logger.info("视频流进程已终止")
                except Exception as e:
                    logger.error(f"终止视频流进程时出错: {str(e)}")
                finally:
                    camera_process = None

def cleanup():
    """清理资源"""
    global camera_process, is_shutting_down
    is_shutting_down = True
    if camera_process:
        try:
            os.killpg(os.getpgid(camera_process.pid), signal.SIGTERM)
            logger.info("已清理相机进程")
        except Exception as e:
            logger.error(f"清理相机进程时出错: {str(e)}")
    # 确保所有相机进程都被终止
    kill_camera_processes() 